package lol.clann.bukkit.pluginboot.command;

import lol.clann.bukkit.pluginboot.util.ServerUtils;
import lol.clann.clannboot.context.BeanContext;
import lol.clann.clannboot.context.ModuleContext;
import lol.clann.clannboot.module.Module;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.OfflinePlayer;
import org.bukkit.World;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.nutz.castor.Castors;
import org.nutz.castor.FailToCastObjectException;

import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.*;

/**
 * @author pyz
 * @date 2018/7/22 下午5:27
 */
public class ParamParsers {

    private static final Map<Class, ParamParser> parsers = new HashMap<>();
    private static final Castors CASTORS = Castors.me();
    private static ServerUtils serverUtils;

    static {
        try {
            ParamParser simpleParser = (arg, type) -> {
                try {
                    return CASTORS.castTo(arg, type);
                } catch (FailToCastObjectException | NumberFormatException e) {
                    throw new ParameterParseException("参数错误");
                }
            };
            registerParser(byte.class, simpleParser);
            registerParser(Byte.class, simpleParser);
            registerParser(short.class, simpleParser);
            registerParser(Short.class, simpleParser);
            registerParser(int.class, simpleParser);
            registerParser(Integer.class, simpleParser);
            registerParser(long.class, simpleParser);
            registerParser(Long.class, simpleParser);
            registerParser(float.class, simpleParser);
            registerParser(Float.class, simpleParser);
            registerParser(double.class, simpleParser);
            registerParser(Double.class, simpleParser);
            registerParser(boolean.class, simpleParser);
            registerParser(Boolean.class, simpleParser);
            registerParser(String.class, simpleParser);

            ParamParser<Player> cPlayer = (arg, type) -> {
                Player p = getServerUtils().getPlayer(arg);
                if (p == null) {
                    throw new ParameterParseException("该玩家不存在或者不在线:" + arg);
                } else {
                    return p;
                }
            };
            registerParser(Player.class, cPlayer);


            ParamParser<OfflinePlayer> cOfflinePlayer = (arg, type) -> {
                OfflinePlayer p = getServerUtils().getOfflinePlayer(arg);
                if (p == null) {
                    throw new ParameterParseException("该玩家不存在:" + arg);
                } else {
                    return p;
                }
            };
            registerParser(OfflinePlayer.class, cOfflinePlayer);


            ParamParser<Material> cMaterial = (arg, type) -> {
                Material material;
                try {
                    Integer id = Integer.valueOf(arg);
                    material = Material.getMaterial(id);
                } catch (NumberFormatException e) {
                    material = Material.getMaterial(arg);
                }
                if (material == null) {
                    throw new ParameterParseException("该物品不存在,id=" + arg);
                } else {
                    return material;
                }
            };
            registerParser(Material.class, cMaterial);

            ParamParser<World> cWorld = (arg, type) -> {
                World w = Bukkit.getWorld(arg);
                if (w == null) {
                    throw new ParameterParseException("无效的世界名:worldName=" + arg);
                }
                return w;
            };
            registerParser(World.class, cWorld);

            ParamParser<Module> cModule = (arg, type) -> {
                Module param = ModuleContext.getModule(arg);
                if (param == null) {
                    throw new ParameterParseException("无效的ModuleId:moduleId=" + arg);
                }
                return param;
            };
            registerParser(Module.class, cModule);
        } catch (Throwable e) {
            throw new RuntimeException(e);
        }
    }

    public static ParamParser getParser(Class type) {
        return parsers.get(type);
    }

    public static synchronized <T> void registerParser(Class<T> type, ParamParser<T> parser) {
        if (parsers.containsKey(type)) {
            throw new RuntimeException("参数转换器" + type.getName() + "已存在");
        }
        parsers.put(type, parser);
    }

    public static Object[] parse(CommandSender commandSender, Method method, String[] args) {
        Parameter[] parameters = method.getParameters();
        Set<String> argSet = new HashSet<>(Arrays.asList(args));
        Object[] params = new Object[parameters.length];
        int paramIndex = 0;
        int argIndex = 0;
        while (paramIndex < parameters.length) {
            Parameter parameter = parameters[paramIndex];
            Sender sender = parameter.getAnnotation(Sender.class);
            if (sender != null) {
                params[paramIndex] = commandSender;
                paramIndex++;
                continue;
            }
            Flag flag = parameter.getAnnotation(Flag.class);
            if (flag != null) {
                if (argSet.contains("--" + flag.value())) {
                    params[paramIndex] = true;
                } else {
                    params[paramIndex] = false;
                }
                paramIndex++;
                continue;
            }
            //flag,已经解析到set里去了
            if (argIndex < args.length && args[argIndex].startsWith("--")) {
                argIndex++;
                continue;
            }
            if (paramIndex == parameters.length - 1 && parameter.isVarArgs()) {
                //最后一个参数,且是可变参数
                Class mType = parameter.getType();
                Class type = mType.getComponentType();
                List<String> leftArgs = new ArrayList<>();
                for (; argIndex < args.length; argIndex++) {
                    if (args[argIndex].startsWith("--")) {
                        continue;
                    }
                    leftArgs.add(args[argIndex]);
                }
                int length = leftArgs.size();
                Object varParam = Array.newInstance(type, length);
                ParamParser parser = parsers.get(type);
                for (int j = 0; j < length; j++) {
                    Array.set(varParam, j, parser.parse(leftArgs.get(j), type));
                }
                params[paramIndex] = varParam;
                paramIndex++;
                continue;
            } else if (paramIndex < params.length && argIndex < args.length) {
                ParamParser parser = parsers.get(parameter.getType());
                //在实例化command时,已经校验过了,参数列表中的都是可解析的
                params[paramIndex] = parser.parse(args[argIndex], parameter.getType());
                paramIndex++;
                argIndex++;
                continue;
            }
            OptionalParam optionalParam = parameter.getAnnotation(OptionalParam.class);
            if (argIndex >= args.length) {
                if (optionalParam != null) {
                    params[paramIndex] = null;
                    paramIndex++;
                } else {
                    throw new ParameterParseException("参数不足");
                }
            }
        }
        return params;
    }

    private static ServerUtils getServerUtils() {
        if (serverUtils == null) {
            serverUtils = BeanContext.getBean(ServerUtils.class);
        }
        return serverUtils;
    }
}
